#include "tlswrap.h"

/*

static void my_debug(void *ctx, int level,
    const char *file, int line,
    const char *str)
{
    ((void)level);

    printf("%s\n", str);
}


#define _SRV_KEY_RSA_PEM \
    "-----BEGIN RSA PRIVATE KEY-----\r\n" \
    "MIIEpAIBAAKCAQEAwU2j3efNHdEE10lyuJmsDnjkOjxKzzoTFtBa5M2jAIin7h5r\r\n" \
    "lqdStJDvLXJ6PiSa/LY0rCT1d+AmZIycsCh9odrqjObJHJa8/sEEUrM21KP64bF2\r\n" \
    "2JDBYbRmUjaiJlOqq3ReB30Zgtsq2B+g2Q0cLUlm91slc0boC4pPaQy1AJDh2oIQ\r\n" \
    "Zn2uVCuLZXmRoeJhw81ASQjuaAzxi4bSRr/QuKoRAx5/VqgaHkQYDw+Fi9qLRF7i\r\n" \
    "GMZiL8dmjfpd2H3zJ4kpAcWQDj8n8TDISg7v1t7HxydrxwU9esQCPJodPg/oNJhb\r\n" \
    "y3NLUpbYEaIsgIhpOVrTD7DeWS8Rx/fqEgEwlwIDAQABAoIBAQCXR0S8EIHFGORZ\r\n" \
    "++AtOg6eENxD+xVs0f1IeGz57Tjo3QnXX7VBZNdj+p1ECvhCE/G7XnkgU5hLZX+G\r\n" \
    "Z0jkz/tqJOI0vRSdLBbipHnWouyBQ4e/A1yIJdlBtqXxJ1KE/ituHRbNc4j4kL8Z\r\n" \
    "/r6pvwnTI0PSx2Eqs048YdS92LT6qAv4flbNDxMn2uY7s4ycS4Q8w1JXnCeaAnYm\r\n" \
    "WYI5wxO+bvRELR2Mcz5DmVnL8jRyml6l6582bSv5oufReFIbyPZbQWlXgYnpu6He\r\n" \
    "GTc7E1zKYQGG/9+DQUl/1vQuCPqQwny0tQoX2w5tdYpdMdVm+zkLtbajzdTviJJa\r\n" \
    "TWzL6lt5AoGBAN86+SVeJDcmQJcv4Eq6UhtRr4QGMiQMz0Sod6ettYxYzMgxtw28\r\n" \
    "CIrgpozCc+UaZJLo7UxvC6an85r1b2nKPCLQFaggJ0H4Q0J/sZOhBIXaoBzWxveK\r\n" \
    "nupceKdVxGsFi8CDy86DBfiyFivfBj+47BbaQzPBj7C4rK7UlLjab2rDAoGBAN2u\r\n" \
    "AM2gchoFiu4v1HFL8D7lweEpi6ZnMJjnEu/dEgGQJFjwdpLnPbsj4c75odQ4Gz8g\r\n" \
    "sw9lao9VVzbusoRE/JGI4aTdO0pATXyG7eG1Qu+5Yc1YGXcCrliA2xM9xx+d7f+s\r\n" \
    "mPzN+WIEg5GJDYZDjAzHG5BNvi/FfM1C9dOtjv2dAoGAF0t5KmwbjWHBhcVqO4Ic\r\n" \
    "BVvN3BIlc1ue2YRXEDlxY5b0r8N4XceMgKmW18OHApZxfl8uPDauWZLXOgl4uepv\r\n" \
    "whZC3EuWrSyyICNhLY21Ah7hbIEBPF3L3ZsOwC+UErL+dXWLdB56Jgy3gZaBeW7b\r\n" \
    "vDrEnocJbqCm7IukhXHOBK8CgYEAwqdHB0hqyNSzIOGY7v9abzB6pUdA3BZiQvEs\r\n" \
    "3LjHVd4HPJ2x0N8CgrBIWOE0q8+0hSMmeE96WW/7jD3fPWwCR5zlXknxBQsfv0gP\r\n" \
    "3BC5PR0Qdypz+d+9zfMf625kyit4T/hzwhDveZUzHnk1Cf+IG7Q+TOEnLnWAWBED\r\n" \
    "ISOWmrUCgYAFEmRxgwAc/u+D6t0syCwAYh6POtscq9Y0i9GyWk89NzgC4NdwwbBH\r\n" \
    "4AgahOxIxXx2gxJnq3yfkJfIjwf0s2DyP0kY2y6Ua1OeomPeY9mrIS4tCuDQ6LrE\r\n" \
    "TB6l9VGoxJL4fyHnZb8L5gGvnB1bbD8cL6YPaDiOhcRseC9vBiEuVg==\r\n" \
    "-----END RSA PRIVATE KEY-----\r\n"

#define tls_debug_level 2

int s_tls_init_bio(mbedtls_session_t* session, void *entropy, size_t len)
{
    mbedtls_net_init(&session->mbedNetCtx);
    mbedtls_ssl_init(&session->mbedSslCtx);
    mbedtls_ssl_config_init(&session->mbedSslConf);
    mbedtls_ctr_drbg_init(&session->mbedDrbgCtx);
    mbedtls_x509_crt_init(&session->mbedX509Crt);
    mbedtls_entropy_init(&(session->mbedEtpyCtx));
    mbedtls_ssl_conf_dbg(&session->mbedSslConf, my_debug, stdout);
    mbedtls_ctr_drbg_seed(&session->mbedDrbgCtx,
                            mbedtls_entropy_func,
                            &session->mbedEtpyCtx,
                            (unsigned char *)entropy,
                            len);

    mbedtls_pk_parse_key(&session->mbedPkey, (const unsigned char *) mbedtls_test_srv_key,
                         mbedtls_test_srv_key_len, NULL, 0 );

    mbedtls_x509_crt_parse(&session->mbedX509Crt,
                                 (const unsigned char*) mbedtls_test_srv_crt,  mbedtls_test_srv_crt_len );

    mbedtls_ssl_config_defaults(&session->mbedSslConf,
                                MBEDTLS_SSL_IS_SERVER,
                                MBEDTLS_SSL_TRANSPORT_STREAM,
                                MBEDTLS_SSL_PRESET_DEFAULT);

    mbedtls_ssl_conf_authmode(&session->mbedSslConf, MBEDTLS_SSL_VERIFY_OPTIONAL);
    mbedtls_ssl_conf_ca_chain(&session->mbedSslConf, &session->mbedX509Crt, NULL);

    mbedtls_ssl_conf_rng(&session->mbedSslConf, mbedtls_ctr_drbg_random, &session->mbedDrbgCtx);
    mbedtls_ssl_conf_dbg(&session->mbedSslConf, my_debug, stdout);


    mbedtls_ssl_set_bio(&session->mbedSslCtx,
                        &session->mbedNetCtx, mbedtls_net_send, mbedtls_net_recv, NULL);


    mbedtls_ssl_conf_ca_chain( &session->mbedSslConf, session->mbedX509Crt.next, NULL );
    mbedtls_ssl_conf_own_cert( &session->mbedSslConf,
                              &session->mbedX509Crt, &session->mbedPkey);


    mbedtls_ssl_conf_read_timeout(&session->mbedSslConf, 30000);

    mbedtls_ssl_setup(&session->mbedSslCtx, &session->mbedSslConf);

    mbedtls_debug_set_threshold(tls_debug_level);
    return 0;
}


int c_tls_init_bio(mbedtls_session_t* session, void *entropy, size_t len)
{
    mbedtls_net_init(&session->mbedNetCtx);
    mbedtls_ssl_init(&session->mbedSslCtx);
    mbedtls_ssl_config_init(&session->mbedSslConf);
    mbedtls_ctr_drbg_init(&session->mbedDrbgCtx);
    mbedtls_x509_crt_init(&session->mbedX509Crt);
    mbedtls_entropy_init(&(session->mbedEtpyCtx));
    //mbedtls_ssl_conf_dbg(&session->mbedSslConf, my_debug, stdout);
    mbedtls_ctr_drbg_seed(&session->mbedDrbgCtx,
                            mbedtls_entropy_func,
                            &session->mbedEtpyCtx,
                            (unsigned char *)entropy,
                            len);

    mbedtls_ssl_config_defaults(&session->mbedSslConf,
                                MBEDTLS_SSL_IS_CLIENT,
                                MBEDTLS_SSL_TRANSPORT_STREAM,
                                MBEDTLS_SSL_PRESET_DEFAULT);

    mbedtls_ssl_conf_authmode(&session->mbedSslConf, MBEDTLS_SSL_VERIFY_OPTIONAL);
    mbedtls_ssl_conf_ca_chain(&session->mbedSslConf, &session->mbedX509Crt, NULL);
    mbedtls_ssl_conf_rng(&session->mbedSslConf, mbedtls_ctr_drbg_random, &session->mbedDrbgCtx);
    mbedtls_ssl_conf_dbg(&session->mbedSslConf, my_debug, stdout);
    mbedtls_ssl_setup(&session->mbedSslCtx, &session->mbedSslConf);

    mbedtls_ssl_conf_read_timeout(&session->mbedSslConf, 30000);

    mbedtls_ssl_set_bio(&session->mbedSslCtx,&session->mbedNetCtx, mbedtls_net_send, mbedtls_net_recv, NULL);

    mbedtls_debug_set_threshold(tls_debug_level);

    return 0;
}

int open_handshake(mbedtls_session_t* session)
{
    int open = 0;
    int rc = 0;
    while ((rc = mbedtls_ssl_handshake(&session->mbedSslCtx)) != 0)
    {
        if (rc != MBEDTLS_ERR_SSL_WANT_READ && rc != MBEDTLS_ERR_SSL_WANT_WRITE) {
            break;
        }

    }

    open = session->mbedSslCtx.state == MBEDTLS_SSL_HANDSHAKE_OVER;
    return open;
}
int get_verify_result(mbedtls_session_t* session, char* buf, size_t size)
{
    int open = 1;
    uint32_t flags;

    if ((flags = mbedtls_ssl_get_verify_result(&session->mbedSslCtx)) != 0)
    {
        open = 0;
        char vrfy_buf[512];
        mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "!", flags);
    }
    return open;
}

static inline size_t iossl_ep_len(const mbedtls_ssl_context* ssl)
{
#if defined(MBEDTLS_SSL_PROTO_DTLS)
    if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM)
        return (2);
#else
    ((void)ssl);
#endif
    return (0);
}

static void iossl_update_out_pointers(mbedtls_ssl_context* ssl, mbedtls_ssl_transform* transform)
{
#if defined(MBEDTLS_SSL_PROTO_DTLS)
    if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
        ssl->out_ctr = ssl->out_hdr + 3;
        ssl->out_len = ssl->out_hdr + 11;
        ssl->out_iv = ssl->out_hdr + 13;
    } else
#endif
    {
        ssl->out_ctr = ssl->out_hdr - 8;
        ssl->out_len = ssl->out_hdr + 3;
        ssl->out_iv = ssl->out_hdr + 5;
    }

    if (transform != NULL && ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2) {
        ssl->out_msg = ssl->out_iv + transform->ivlen - transform->fixed_ivlen;
    } else
        ssl->out_msg = ssl->out_iv;
}

#define SSL_DONT_FORCE_FLUSH 0
#define SSL_FORCE_FLUSH      1

int tls_encrypt_buf(mbedtls_session_t* session, unsigned char* ptr, size_t size)
{
    unsigned i;
    int ret, done = 0;
    uint8_t flush = SSL_FORCE_FLUSH;

    size_t protected_record_size;
    mbedtls_ssl_context* ssl = &session->mbedSslCtx;

    ssl->out_msglen = size;
    ssl->out_msgtype = MBEDTLS_SSL_MSG_APPLICATION_DATA;
    memcpy(ssl->out_msg, ptr, size);


    size_t len = ssl->out_msglen;
    ssl->out_hdr[0] = (unsigned char)ssl->out_msgtype;
    mbedtls_ssl_write_version(ssl->major_ver, ssl->minor_ver,ssl->conf->transport, ssl->out_hdr + 1);
    memcpy(ssl->out_ctr, ssl->cur_out_ctr, 8);
    ssl->out_len[0] = (unsigned char)(len >> 8);
    ssl->out_len[1] = (unsigned char)(len);

    if (ssl->transform_out != NULL) {
        if ((ret = ssl_encrypt_buf(ssl)) != 0) {
            return (ret);
        }

        len = ssl->out_msglen;
        ssl->out_len[0] = (unsigned char)(len >> 8);
        ssl->out_len[1] = (unsigned char)(len);
    }
    protected_record_size = len + mbedtls_ssl_hdr_len(ssl);


#if defined(MBEDTLS_SSL_PROTO_DTLS)
        if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) {
            ret = ssl_get_remaining_space_in_datagram(ssl);
            if (ret < 0)
                return (ret);

            if (protected_record_size > (size_t)ret) {
                return (MBEDTLS_ERR_SSL_INTERNAL_ERROR);
            }
        }
#endif


    ssl->out_left += protected_record_size;
    ssl->out_hdr += protected_record_size;
    iossl_update_out_pointers(ssl, ssl->transform_out);

    for (i = 8; i > iossl_ep_len(ssl); i--)
        if (++ssl->cur_out_ctr[i - 1] != 0)
            break;

#if defined(MBEDTLS_SSL_PROTO_DTLS)
    if (ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && flush == SSL_DONT_FORCE_FLUSH) {

        size_t remaining;
        ret = ssl_get_remaining_payload_in_datagram(ssl);
        if (ret < 0) {
            MBEDTLS_SSL_DEBUG_RET(1, "ssl_get_remaining_payload_in_datagram", ret);
            return (ret);
        }

        remaining = (size_t)ret;
        if (remaining == 0) {
            flush = SSL_FORCE_FLUSH;
        } else {
            MBEDTLS_SSL_DEBUG_MSG(2, ("Still %u bytes available in current datagram", (unsigned)remaining));
        }

    }
#endif

    return 0;
}
int tls_decryption_buf(mbedtls_session_t* session, unsigned char* ptr, size_t size)
{
    return 0;
}
*/
